package com.onehouse.domain.payment.service;

import com.google.common.eventbus.EventBus;
import com.onehouse.domain.payment.adapter.event.CheckInOrderPaymentPaidOffEvent;
import com.onehouse.domain.payment.adapter.event.CheckInOrderPaymentTerminateEvent;
import com.onehouse.domain.payment.adapter.repository.IPaymentRepository;
import com.onehouse.domain.payment.model.entity.OrderPaymentRequest;
import com.onehouse.domain.payment.model.entity.Payment;
import com.onehouse.domain.payment.model.valobj.PaymentMethod;
import com.onehouse.domain.payment.model.valobj.PaymentStatus;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Service
public class PaymentRequestService implements IPaymentRequestService {
    private static final Logger logger = LogManager.getLogger(PaymentRequestService.class);

    // 使用ConcurrentHashMap确保线程安全
    private static final Map<String, String> paymentIdToOrderIdMap = new ConcurrentHashMap<>();
    private static final Map<String, OrderPaymentRequest> orderIdToRequestMap = new ConcurrentHashMap<>();

    // 前端进行现金支付所需的所有信息都从这取，key是paymentId.
    private static final Map<String, String> prepareToBePaidCashPayOrderMap = new ConcurrentHashMap<>();
    
     // 前端进行Ali支付所需的所有信息都从这取
    private static final Map<String, String> prepareToBePaidAliPayOrderMap = new ConcurrentHashMap<>();

    @Autowired
    private EventBus eventBus;

    @Autowired
    private CashPayService cashPayService;

    @Autowired
    private IPaymentRepository paymentRepository;

    @Override
    public void handleOrderPaymentPostEvent(String orderId, BigDecimal amount) {
        logger.info("处理订单支付事件: orderId={}, amount={}", orderId, amount);
        
        // 创建支付请求
        OrderPaymentRequest paymentRequest = new OrderPaymentRequest();
        paymentRequest.setOrderId(orderId);
        paymentRequest.setPayments(new ArrayList<>());

        // 创建支付记录
        Payment cashPayment = Payment.builder()
                .orderId(paymentRequest.getOrderId())
                .amount(amount)
                .status(PaymentStatus.PENDING)
                .createTime(LocalDateTime.now())
                .paymentMethod(PaymentMethod.CASH)
                .build();

        Payment aliPayment = Payment.builder()
                .orderId(paymentRequest.getOrderId())
                .amount(amount)
                .status(PaymentStatus.PENDING)
                .createTime(LocalDateTime.now())
                .paymentMethod(PaymentMethod.ALIPAY)
                .build();

        String cashPaymentId = cashPayService.preparePaymentInform(orderId, amount, "xj");
        cashPayment.setPaymentId(cashPaymentId);

        // 实际上阿里支付的订单号不是这样，每种支付的支付单号都有其内在意义
        String aliPaymentId = cashPayService.preparePaymentInform(orderId, amount, "al");
        aliPayment.setPaymentId(aliPaymentId);
        
        // 此处现金支付所需所有信息已准备完成，可以通知前端获取
        // 怎么通知前端？——不通知，前端通过循环轮询进行获取
        // 根据orderId一直轮询查询，获取支付所需信息

        // 使用putIfAbsent确保不会覆盖已存在的映射
        paymentIdToOrderIdMap.putIfAbsent(cashPaymentId, orderId);
        prepareToBePaidCashPayOrderMap.putIfAbsent(orderId, cashPaymentId);

        paymentRequest.getPayments().add(cashPayment);
        paymentRequest.getPayments().add(aliPayment);

        // TODO 向AliPayPrepareService请求对应的二维码图片，在此期间由AliPay形成payId，并与简写Id生成机制配合
        // TODO eventBus.post(aliEvent);

        orderIdToRequestMap.putIfAbsent(paymentRequest.getOrderId(), paymentRequest);
        logger.info("订单支付请求创建完成: orderId={}, cashPaymentId={}", orderId, cashPaymentId);
    }

    @Override
    public void handleMethodPaymentPaidOffEvent(String paymentId) {
        logger.info("处理支付完成事件: paymentId={}", paymentId);
        String orderId = paymentIdToOrderIdMap.get(paymentId);

        if (orderId == null) {
            logger.error("未找到支付ID对应的订单: paymentId={}", paymentId);
            return;
        }

        OrderPaymentRequest orderPaymentRequest = orderIdToRequestMap.get(orderId);
        if (orderPaymentRequest == null) {
            logger.error("未找到订单对应的支付请求: orderId={}", orderId);
            return;
        }

        orderPaymentRequest.handleMethodPaymentPaidOff(paymentId);

        // 此处进行payment的持久化
        for(Payment payment : orderPaymentRequest.getPayments()) {
            paymentRepository.doSavePayment(payment);
        }

        paymentIdToOrderIdMap.remove(paymentId);
        orderIdToRequestMap.remove(orderId);
        prepareToBePaidCashPayOrderMap.remove(orderId);
        prepareToBePaidAliPayOrderMap.remove(orderId);

        CheckInOrderPaymentPaidOffEvent checkInOrderPaymentPaidOffEvent = CheckInOrderPaymentPaidOffEvent.builder()
                .checkInOrderId(orderId)
                .paymentId(paymentId)
                .build();

        eventBus.post(checkInOrderPaymentPaidOffEvent);
        // 如果第三方支付服务需要回调，此处返回对应信息
        logger.info("支付完成事件处理完成: orderId={}, paymentId={}", orderId, paymentId);
    }

    // 异常终止订单支付
    public void terminateOrderPaymentRequest(String orderId, String terminateReason) {
        OrderPaymentRequest orderPaymentRequest = orderIdToRequestMap.get(orderId);

        orderPaymentRequest.handleTerminateOrderPaymentRequest();

        // 此处进行payment的持久化
        for(Payment payment : orderPaymentRequest.getPayments()) {
            paymentRepository.doSavePayment(payment);
        }

        CheckInOrderPaymentTerminateEvent checkInOrderPaymentTerminateEvent =  CheckInOrderPaymentTerminateEvent.builder()
                .orderId(orderId)
                .terminateReason(terminateReason)
                .build();

        eventBus.post(checkInOrderPaymentTerminateEvent);
    }

    @Override
    public BigDecimal handleCashPaymentPostEvent(String paymentId, BigDecimal cashAmount) {
        logger.info("处理现金支付事件: orderId={}, cashAmount={}", paymentId, cashAmount);
        String oredrId = paymentIdToOrderIdMap.get(paymentId);
        OrderPaymentRequest orderPaymentRequest = orderIdToRequestMap.get(oredrId);
        if (orderPaymentRequest == null) {
            logger.error("未找到订单对应的支付请求: orderId={}", oredrId);
            return BigDecimal.ZERO.subtract(BigDecimal.ONE);
        }

        for(Payment payment : orderPaymentRequest.getPayments()) {
            if (payment.getPaymentMethod() == PaymentMethod.CASH) {
                // 如果现金支付的金额大于订单金额，则进行支付，并返回找零金额
                if(cashAmount.compareTo(payment.getAmount()) > 0) {
                    this.handleMethodPaymentPaidOffEvent(payment.getPaymentId());
                    BigDecimal change = cashAmount.subtract(payment.getAmount());
                    logger.info("现金支付成功，找零: {}", change);
                    return change;
                } else {
                    logger.warn("现金支付金额不足: required={}, provided={}", payment.getAmount(), cashAmount);
                    return BigDecimal.ZERO.subtract(BigDecimal.ONE);
                }
            }
        }
        logger.error("未找到现金支付记录: orderId={}", oredrId);
        return BigDecimal.ZERO.subtract(BigDecimal.ONE);
    }

    @Override
    public boolean validateMethodPaymentIsPaidOff(String paymentId) {
        Payment validatePayment = paymentRepository.getPaymentById(paymentId);
        if (validatePayment.getStatus() == PaymentStatus.SUCCESS) {
            return true;
        }
        return false;
    }

    @Override
    public boolean validateOrderPaymentIsPaidOff(String orderId) {
        OrderPaymentRequest orderPaymentRequest = orderIdToRequestMap.get(orderId);
        for (Payment payment : orderPaymentRequest.getPayments()) {
            if (payment.getStatus() == PaymentStatus.SUCCESS) {
                return true;
            }
        }
        return false;
    }

    @Override
    public String getCashPaymentRequiredInfo(String orderId) {
        return this.prepareToBePaidCashPayOrderMap.get(orderId);
    }
}
